package cn.jtfadmin.file.manager.elfinder.config;


import br.com.trustsystems.elfinder.ElFinderConstants;
import br.com.trustsystems.elfinder.command.CommandFactory;
import br.com.trustsystems.elfinder.configuration.jaxb.ElfinderConfiguration;
import br.com.trustsystems.elfinder.core.Volume;
import br.com.trustsystems.elfinder.core.VolumeSecurity;
import br.com.trustsystems.elfinder.core.impl.DefaultVolumeSecurity;
import br.com.trustsystems.elfinder.core.impl.SecurityConstraint;
import br.com.trustsystems.elfinder.service.ElfinderStorage;
import br.com.trustsystems.elfinder.service.ElfinderStorageFactory;
import br.com.trustsystems.elfinder.service.VolumeSources;
import br.com.trustsystems.elfinder.service.impl.DefaultElfinderStorage;
import br.com.trustsystems.elfinder.service.impl.DefaultElfinderStorageFactory;
import br.com.trustsystems.elfinder.service.impl.DefaultThumbnailWidth;
import br.com.trustsystems.elfinder.support.locale.LocaleUtils;
import cn.jtfadmin.base.filesystem.LocalFileSystemConfig;
import cn.jtfadmin.base.filesystem.config.FileResourceConfig;
import cn.jtfadmin.base.filesystem.config.FileResourceConfigDTO;
import cn.jtfadmin.base.filesystem.config.FileSystem;
import cn.jtfadmin.base.filesystem.config.local.LocalFileSystemImpl;
import cn.jtfadmin.base.filesystem.constant.Constants;
import cn.jtfadmin.base.lang.common.utils.RequestUtils;
import cn.jtfadmin.base.lang.config.module.DefaultModuleInfoDTO;
import cn.jtfadmin.base.lang.config.module.ModuleInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.*;



@Configuration()
@ComponentScan(
        basePackages = {"br.com.trustsystems.elfinder"},
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Configuration.class)}
)
@Controller
public class FileManagerElfinderApplication {

//    @Autowired
//    private LocalFileSystemImpl fileSystem;

    @Bean
    public ModuleInfo fileManagerModuleInfo(){
        return new DefaultModuleInfoDTO("fileManager", "在线文件管理系统", "在线文件管理系统", getClass().getPackage().getName());
    }



    @Bean(name = "commandFactory")
    @ConditionalOnMissingBean(name = "commandFactory")
    public CommandFactory getCommandFactory() {
        CommandFactory commandFactory = new CommandFactory();
        commandFactory.setClassNamePattern("br.com.trustsystems.elfinder.command.%sCommand");
        return commandFactory;
    }

    @Bean()
    @ConditionalOnMissingBean(value = FileUserVisiterConfig.class)
    public FileUserVisiterConfig fileUserVisiterConfig(){
        return new FileUserVisiterConfig() {};
    }

    @Bean(name = "elfinderStorageFactory")
    @ConditionalOnMissingBean(name = "elfinderStorageFactory")
    public ElfinderStorageFactory getElfinderStorageFactory(ElfinderStorage storage) {
        DefaultElfinderStorageFactory elfinderStorageFactory = new DefaultElfinderStorageFactory();
        elfinderStorageFactory.setElfinderStorage(storage);
        return elfinderStorageFactory;
    }

    @Bean(name = "elfinderStorage")
    @ConditionalOnMissingBean(name = "elfinderStorage")
    public ElfinderStorage getElfinderStorage(LocalFileSystemImpl fileSystem) {
        DefaultElfinderStorage defaultElfinderStorage = new DefaultElfinderStorage();
        FileUserVisiterConfig fileUserVisiterConfig = fileUserVisiterConfig();
        // creates thumbnail
        DefaultThumbnailWidth defaultThumbnailWidth = new DefaultThumbnailWidth();
        defaultThumbnailWidth.setThumbnailWidth(80);// 缺省宽度

        // creates volumes, volumeIds, volumeLocale and volumeSecurities
        Character defaultVolumeId = 'A';
        List<ElfinderConfiguration.Volume> elfinderConfigurationVolumes = new ArrayList<>();
        Iterator<FileResourceConfigDTO> fileResourceConfigList = fileSystem.getAllFileConfig().iterator();
       fileResourceConfigList.forEachRemaining(t->{
            boolean readable = fileUserVisiterConfig.readable(t);
           if(!readable){
               return;
           }
           ElfinderConfiguration.Volume volume = new ElfinderConfiguration.Volume();
           volume.setSource("filesystem");
           String describe = t.getDescribe();
           if(StringUtils.hasText(describe)){
               volume.setAlias(describe);
           }else {
               volume.setAlias(t.getDir());
           }
           volume.setPath(Paths.get(fileSystem.getFileBaseDir(), t.getDir()).toString());
           volume.setLocale("zh_CN");
           ElfinderConfiguration.Volume.Constraint constraint = new ElfinderConfiguration.Volume.Constraint();
           constraint.setLocked(fileUserVisiterConfig.locked(t));
           constraint.setReadable(readable);
           constraint.setWritable(fileUserVisiterConfig.writable(t));
           volume.setConstraint(constraint);
           elfinderConfigurationVolumes.add(volume);
       });

        List<Volume> elfinderVolumes = new ArrayList<>(elfinderConfigurationVolumes.size());
        Map<Volume, String> elfinderVolumeIds = new HashMap<>(elfinderConfigurationVolumes.size());
        Map<Volume, Locale> elfinderVolumeLocales = new HashMap<>(elfinderConfigurationVolumes.size());
        List<VolumeSecurity> elfinderVolumeSecurities = new ArrayList<>();

        // creates volumes
        for (ElfinderConfiguration.Volume elfinderConfigurationVolume : elfinderConfigurationVolumes) {

            final String alias = elfinderConfigurationVolume.getAlias();
            final String path = elfinderConfigurationVolume.getPath();
            final String source = elfinderConfigurationVolume.getSource();
            final String locale = elfinderConfigurationVolume.getLocale();
            final boolean isLocked = elfinderConfigurationVolume.getConstraint().isLocked();
            final boolean isReadable = elfinderConfigurationVolume.getConstraint().isReadable();
            final boolean isWritable = elfinderConfigurationVolume.getConstraint().isWritable();

            // creates new volume
            Volume volume = VolumeSources.of(source).newInstance(alias, path);

            elfinderVolumes.add(volume);
            elfinderVolumeIds.put(volume, Character.toString(defaultVolumeId));
            elfinderVolumeLocales.put(volume, LocaleUtils.toLocale(locale));

            // creates security constraint
            SecurityConstraint securityConstraint = new SecurityConstraint();
            securityConstraint.setLocked(isLocked);
            securityConstraint.setReadable(isReadable);
            securityConstraint.setWritable(isWritable);

            // creates volume pattern and volume security
            final String volumePattern = Character.toString(defaultVolumeId) + ElFinderConstants.ELFINDER_VOLUME_SERCURITY_REGEX;
            elfinderVolumeSecurities.add(new DefaultVolumeSecurity(volumePattern, securityConstraint));

            // prepare next volumeId character
            defaultVolumeId++;
        }

        defaultElfinderStorage.setThumbnailWidth(defaultThumbnailWidth);
        defaultElfinderStorage.setVolumes(elfinderVolumes);
        defaultElfinderStorage.setVolumeIds(elfinderVolumeIds);
        defaultElfinderStorage.setVolumeLocales(elfinderVolumeLocales);
        defaultElfinderStorage.setVolumeSecurities(elfinderVolumeSecurities);

        return defaultElfinderStorage;
    }


    /**
     * 缺省的文件管理器页面
     * @return
     */
    @RequestMapping(value = Constants.FILE_MANAGER_WEB_URL)
    public String defaultFileManager(){
        return "redirect:/webjars/elfinder/2.1.53/elfinder.html";
    }

    /**
     * 文件管理器页面
     * @throws IOException
     */
    @GetMapping(value = "/webjars/elfinder/2.1.53/main.default.js", produces="application/javascript; charset=UTF-8")
    @ResponseBody
    public String requiredJs() throws IOException {
        HttpServletResponse response = RequestUtils.getResponse();
         try(InputStream resourceAsStream = Thread.currentThread()
                 .getContextClassLoader().getResourceAsStream("static/elfinder/2.1.53/js/main.default.js");
         ){

            return StreamUtils.copyToString(resourceAsStream,StandardCharsets.UTF_8);
         }
    }

    /**
     * 文件管理器页面
     * @throws IOException
     */
    @RequestMapping(value = "/webjars/elfinder/2.1.53/elfinder.html", produces = MediaType.TEXT_HTML_VALUE)
    @ResponseBody
    public void fileManager() throws IOException {
        String baseUrl = RequestUtils.getRequestBasePath(RequestUtils.getRequest());
        String connector = baseUrl+"/connector";
        String html = "<!DOCTYPE html>\n" +
                "<html>\n" +
                "\t<head>\n" +
                "\t\t<meta charset=\"utf-8\">\n" +
                "\t\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n" +
                "\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=2\">\n" +
                "\t\t<title>elFinder 2.1.x source version with PHP connector</title>\n" +
                "\n" +
                "\t\t<!-- Require JS (REQUIRED) -->\n" +
                "\t\t<!-- Rename \"main.default.js\" to \"main.js\" and edit it if you need configure elFInder options or any things -->\n" +
//                "\t\t<script data-main=\"./main.default.js\" src=\"//cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js\"></script>\n" +
                "\t\t<script data-main=\"./main.default.js\" src=\""+RequestUtils.getRequest().getContextPath()+"/elfinder/2.1.53/js/require.min.js\"></script>\n" +
                "\t\t<script>\n" +
                "\t\t\tdefine('elFinderConfig', {\n" +
                "\t\t\t\t// elFinder options (REQUIRED)\n" +
                "\t\t\t\t// Documentation for client options:\n" +
                "\t\t\t\t// https://github.com/Studio-42/elFinder/wiki/Client-configuration-options\n" +
                "\t\t\t\tdefaultOpts : {\n" +
                "\t\t\t\t\theight: '100%',\n"+
                "\t\t\t\t\turl : '"+connector+"', // or connector.maximal.php : connector URL (REQUIRED)\n" +
                "\t\t\t\t\tcommandsOptions : {\n" +
                "\t\t\t\t\t\tedit : {\n" +
                "\t\t\t\t\t\t\textraOptions : {\n" +
                "\t\t\t\t\t\t\t\t// set API key to enable Creative Cloud image editor\n" +
                "\t\t\t\t\t\t\t\t// see https://console.adobe.io/\n" +
                "\t\t\t\t\t\t\t\tcreativeCloudApiKey : '',\n" +
                "\t\t\t\t\t\t\t\t// browsing manager URL for CKEditor, TinyMCE\n" +
                "\t\t\t\t\t\t\t\t// uses self location with the empty value\n" +
                "\t\t\t\t\t\t\t\tmanagerUrl : ''\n" +
                "\t\t\t\t\t\t\t}\n" +
                "\t\t\t\t\t\t},\n" +
                "\t\t\t\t\t\tquicklook : {\n" +
                "\t\t\t\t\t\t\t// to enable CAD-Files and 3D-Models preview with sharecad.org\n" +
                "\t\t\t\t\t\t\tsharecadMimes : ['image/vnd.dwg', 'image/vnd.dxf', 'model/vnd.dwf', 'application/vnd.hp-hpgl', 'application/plt', 'application/step', 'model/iges', 'application/vnd.ms-pki.stl', 'application/sat', 'image/cgm', 'application/x-msmetafile'],\n" +
                "\t\t\t\t\t\t\t// to enable preview with Google Docs Viewer\n" +
                "\t\t\t\t\t\t\tgoogleDocsMimes : ['application/pdf', 'image/tiff', 'application/vnd.ms-office', 'application/msword', 'application/vnd.ms-word', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/postscript', 'application/rtf'],\n" +
                "\t\t\t\t\t\t\t// to enable preview with Microsoft Office Online Viewer\n" +
                "\t\t\t\t\t\t\t// these MIME types override \"googleDocsMimes\"\n" +
                "\t\t\t\t\t\t\tofficeOnlineMimes : ['application/vnd.ms-office', 'application/msword', 'application/vnd.ms-word', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.presentation']\n" +
                "\t\t\t\t\t\t}\n" +
                "\t\t\t\t\t},\n" +
                "\t\t\t\t\t// bootCalback calls at before elFinder boot up \n" +
                "\t\t\t\t\tbootCallback : function(fm, extraObj) {\n" +
                "\t\t\t\t\t\t/* any bind functions etc. */\n" +
                "\t\t\t\t\t\tfm.bind('init', function() {\n" +
                "\t\t\t\t\t\t\t// any your code\n" +
                "\t\t\t\t\t\t});\n" +
                "\t\t\t\t\t\t// for example set document.title dynamically.\n" +
                "\t\t\t\t\t\tvar title = document.title;\n" +
                "\t\t\t\t\t\tfm.bind('open', function() {\n" +
                "\t\t\t\t\t\t\tvar path = '',\n" +
                "\t\t\t\t\t\t\t\tcwd  = fm.cwd();\n" +
                "\t\t\t\t\t\t\tif (cwd) {\n" +
                "\t\t\t\t\t\t\t\tpath = fm.path(cwd.hash) || null;\n" +
                "\t\t\t\t\t\t\t}\n" +
                "\t\t\t\t\t\t\tdocument.title = path? path + ':' + title : title;\n" +
                "\t\t\t\t\t\t}).bind('destroy', function() {\n" +
                "\t\t\t\t\t\t\tdocument.title = title;\n" +
                "\t\t\t\t\t\t});\n" +
                "\t\t\t\t\t}\n" +
                "\t\t\t\t},\n" +
                "\t\t\t\tmanagers : {\n" +
                "\t\t\t\t\t// 'DOM Element ID': { /* elFinder options of this DOM Element */ }\n" +
                "\t\t\t\t\t'elfinder': {}\n" +
                "\t\t\t\t}\n" +
                "\t\t\t});\n" +
                "\t\t</script>\n" +
                "\t</head>\n" +
                "\t<body>\n" +
                "\n" +
                "\t\t<!-- Element where elFinder will be created (REQUIRED) -->\n" +
                "\t\t<div id=\"elfinder\"></div>\n" +
                "\n" +
                "\t</body>\n" +
                "</html>\n";
        HttpServletResponse response = RequestUtils.getResponse();
        response.getOutputStream().write(html.getBytes(StandardCharsets.UTF_8));
    }
}
